package jesss.commands;

import com.amazonaws.AmazonClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.CopyObjectRequest;
import com.amazonaws.services.s3.model.CopyObjectResult;
import jesss.options.ExtendedGnuParser;
import jesss.options.JesssOptions;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.MissingArgumentException;
import org.apache.commons.cli.Options;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * User: Lee
 * Date: 9/7/13
 * Time: 1:11 PM
 */
public class MoveObjectCommand extends AbstractJesssCommand {
    private Deque<JesssCommand> commandChain = null;

    private JesssOptions jesssOptions = null;
    private Options options = new Options();
    private String sourceBucketName;
    private String sourceKey;
    private String targetBucketName;
    private String targetKey;

    public MoveObjectCommand(JesssOptions jesssOptions) throws Exception {
        this.jesssOptions = jesssOptions;
        this.setShouldDisplayVerbose(jesssOptions.getShouldDisplayVerbose());
        setOptions();
        try {
            parseArgs(jesssOptions.getArgs());
        } catch (Exception e) {
            printUsage();
            throw e;
        }

        this.jesssOptions = new JesssOptions.Builder(jesssOptions.getCommandName()).amazonS3(jesssOptions.getAmazonS3()).shouldDisplayVerbose(jesssOptions.getShouldDisplayVerbose()).args(jesssOptions.getArgs()).build();
        displayMessage("Creating command chain...");
        makeCommandChain(this.jesssOptions);

    }

    private void makeCommandChain(JesssOptions jesssOptions) throws Exception {
        commandChain = new ArrayDeque<JesssCommand>();
        displayMessage("Adding copy object command...");
        commandChain.add(makeCopyObjectCommand(jesssOptions));
        displayMessage("Adding delete object command...");
        commandChain.add(makeDeleteObjectCommand(jesssOptions));
    }

    private JesssCommand makeDeleteObjectCommand(JesssOptions jesssOptions) throws Exception {

        displayMessage(String.format("Creating delete command to delete %s from %s.%n", sourceKey, sourceBucketName));
        JesssCommand deleteCommand = JesssCommandFactoryImpl.getInstance().createCommand(jesssOptions.getAmazonS3(),
                "do",
                jesssOptions.getShouldDisplayVerbose(),
                new String[] {"-bn", sourceBucketName, "-k", sourceKey});

        return deleteCommand;

    }

    private JesssCommand makeCopyObjectCommand(JesssOptions jesssOptions) throws Exception {

        displayMessage(String.format("Creating copy command to copy %s%s to %s%s.%n", sourceKey, sourceBucketName, targetKey, targetBucketName));
        JesssCommand copyCommand = JesssCommandFactoryImpl.getInstance().createCommand(jesssOptions.getAmazonS3(),
                "co",
                jesssOptions.getShouldDisplayVerbose(),
                new String[] {"-sbn", sourceBucketName, "-sk", sourceKey, "-tbn", targetBucketName, "-tk", targetKey});

        return copyCommand;

    }

    /**
     * Copies an object from one bucket to another.
     *
     * @return The CopyObjectResult contains information about the object that was copied.
     */
    @Override
    public CommandResult executeCommand() {

        // copy the object then delete it
        CommandResult result = null;
        try {

            while (!commandChain.isEmpty()) {
                JesssCommand command = commandChain.remove();

                displayMessage(String.format("Executing command.%n"));
                result = command.executeCommand();

                if (result.getResultStatus() == ResultStatus.Error) {
                    displayMessage("An error occurred.");
                    displayMessage(result.getStatusMessage());
                    return result;
                }

                result = new CommandResult();
                result.setResultStatus(ResultStatus.Success);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    private void setOptions() {
        options = new Options();
        options.addOption("sbn", "sourceBucketName", true, "Source bucket name");
        options.addOption("sk", "sourceKey", true, "Source key");
        options.addOption("tbn", "targetBucketName", true, "Target bucket name");
        options.addOption("tk", "targetKey", true, "Target key");
    }

    private void parseArgs(String[] args) throws Exception {
        if (args == null || args.length == 0) {
            printUsage();
        }

        try {
            CommandLineParser parser = new ExtendedGnuParser(true);
            CommandLine cmd = parser.parse(options, args);

            if (cmd.hasOption("sbn")) {
                sourceBucketName = cmd.getOptionValue("sbn");
            } else {
                throw new MissingArgumentException("Missing source bucket name parameter.");
            }

            if (cmd.hasOption("sk")) {
                sourceKey = cmd.getOptionValue("sk");
            } else {
                throw new MissingArgumentException("Missing source key parameter.");
            }

            if (cmd.hasOption("tbn")) {
                targetBucketName = cmd.getOptionValue("tbn");
            } else {
                throw new MissingArgumentException("Missing target bucket name parameter.");
            }

            if (cmd.hasOption("tk")) {
                targetKey = cmd.getOptionValue("tk");
            } else {
                throw new MissingArgumentException("Missing target key parameter.");
            }
        } catch (Exception e) {
            printUsage();
            throw e;
        }
    }

    private void printUsage() {
        System.out.println("Usage:");
        System.out.println("jesss.jesss -cn copyObject -sbn <source bucket> -sk <source key> -tbn <target bucket name> -tk <target key>");
    }
}
